+Wed Sep 10 01:06:44 2003 Kristian Rietveld <kris@gtk.org>
+
+ Big TreeView DnD fixage, makes drops on empty models work, makes
+ TreeStore DnD work and gets rid of gtk-tree-model-drop-append.
+ Related bugs #95362 and #113314. I don't want to touch this code
+ ever again.
+
+ * gtk/gtktreeprivate.h (GtkTreePrivate): add empty_view_drop field.
+
+ * gtk/gtktreednd.c (gtk_tree_get_row_drag_data): add check
+ for selection_data->length.
+
+ * gtk/gtktreeview.c (struct DestRow), (dest_row_free),
+ (set_dest_row), (get_dest_row): we don't store just the row ref
+ anymore, but a struct with the row ref and additional info,
+ (set_destination_row): handle drops on empty space and some
+ style fixes,
+ (get_logical_dest_row): also return path_down_mode/drop_append_mode
+ flags, handle dropping childs on their new parents, rewrite
+ drop append handling into something saner,
+ (gtk_tree_view_drag_motion): show a "drop possible arrow" on empty
+ spaces,
+ (gtk_tree_view_drag_drop): updates for updated backend,
+ (gtk_tree_view_drag_data_received): updates for updated backend,
+ path down mode (treestore DnD) handling,
+ (gtk_tree_view_set_drag_dest_row): set empty_view_drop flag,
+ when we are trying to drop a row on an empty model,
+ (gtk_tree_view_get_drag_dest_row): handle empty_view_drop flag.
+
+ * gtk/gtkliststore.c (gtk_list_store_drag_data_received),
+ (gtk_list_store_row_drop_possible): style and drop-append fixes.
+
+ * gtk/gtktreestore.c (gtk_tree_store_drag_data_received): ditto.
+
2003-09-08 Alexander Larsson <alexl@redhat.com>
* gtk/gtkeventbox.[hc]:
+Wed Sep 10 01:06:44 2003 Kristian Rietveld <kris@gtk.org>
+
+ Big TreeView DnD fixage, makes drops on empty models work, makes
+ TreeStore DnD work and gets rid of gtk-tree-model-drop-append.
+ Related bugs #95362 and #113314. I don't want to touch this code
+ ever again.
+
+ * gtk/gtktreeprivate.h (GtkTreePrivate): add empty_view_drop field.
+
+ * gtk/gtktreednd.c (gtk_tree_get_row_drag_data): add check
+ for selection_data->length.
+
+ * gtk/gtktreeview.c (struct DestRow), (dest_row_free),
+ (set_dest_row), (get_dest_row): we don't store just the row ref
+ anymore, but a struct with the row ref and additional info,
+ (set_destination_row): handle drops on empty space and some
+ style fixes,
+ (get_logical_dest_row): also return path_down_mode/drop_append_mode
+ flags, handle dropping childs on their new parents, rewrite
+ drop append handling into something saner,
+ (gtk_tree_view_drag_motion): show a "drop possible arrow" on empty
+ spaces,
+ (gtk_tree_view_drag_drop): updates for updated backend,
+ (gtk_tree_view_drag_data_received): updates for updated backend,
+ path down mode (treestore DnD) handling,
+ (gtk_tree_view_set_drag_dest_row): set empty_view_drop flag,
+ when we are trying to drop a row on an empty model,
+ (gtk_tree_view_get_drag_dest_row): handle empty_view_drop flag.
+
+ * gtk/gtkliststore.c (gtk_list_store_drag_data_received),
+ (gtk_list_store_row_drop_possible): style and drop-append fixes.
+
+ * gtk/gtktreestore.c (gtk_tree_store_drag_data_received): ditto.
+
2003-09-08 Alexander Larsson <alexl@redhat.com>
* gtk/gtkeventbox.[hc]:
+Wed Sep 10 01:06:44 2003 Kristian Rietveld <kris@gtk.org>
+
+ Big TreeView DnD fixage, makes drops on empty models work, makes
+ TreeStore DnD work and gets rid of gtk-tree-model-drop-append.
+ Related bugs #95362 and #113314. I don't want to touch this code
+ ever again.
+
+ * gtk/gtktreeprivate.h (GtkTreePrivate): add empty_view_drop field.
+
+ * gtk/gtktreednd.c (gtk_tree_get_row_drag_data): add check
+ for selection_data->length.
+
+ * gtk/gtktreeview.c (struct DestRow), (dest_row_free),
+ (set_dest_row), (get_dest_row): we don't store just the row ref
+ anymore, but a struct with the row ref and additional info,
+ (set_destination_row): handle drops on empty space and some
+ style fixes,
+ (get_logical_dest_row): also return path_down_mode/drop_append_mode
+ flags, handle dropping childs on their new parents, rewrite
+ drop append handling into something saner,
+ (gtk_tree_view_drag_motion): show a "drop possible arrow" on empty
+ spaces,
+ (gtk_tree_view_drag_drop): updates for updated backend,
+ (gtk_tree_view_drag_data_received): updates for updated backend,
+ path down mode (treestore DnD) handling,
+ (gtk_tree_view_set_drag_dest_row): set empty_view_drop flag,
+ when we are trying to drop a row on an empty model,
+ (gtk_tree_view_get_drag_dest_row): handle empty_view_drop flag.
+
+ * gtk/gtkliststore.c (gtk_list_store_drag_data_received),
+ (gtk_list_store_row_drop_possible): style and drop-append fixes.
+
+ * gtk/gtktreestore.c (gtk_tree_store_drag_data_received): ditto.
+
2003-09-08 Alexander Larsson <alexl@redhat.com>
* gtk/gtkeventbox.[hc]:
+Wed Sep 10 01:06:44 2003 Kristian Rietveld <kris@gtk.org>
+
+ Big TreeView DnD fixage, makes drops on empty models work, makes
+ TreeStore DnD work and gets rid of gtk-tree-model-drop-append.
+ Related bugs #95362 and #113314. I don't want to touch this code
+ ever again.
+
+ * gtk/gtktreeprivate.h (GtkTreePrivate): add empty_view_drop field.
+
+ * gtk/gtktreednd.c (gtk_tree_get_row_drag_data): add check
+ for selection_data->length.
+
+ * gtk/gtktreeview.c (struct DestRow), (dest_row_free),
+ (set_dest_row), (get_dest_row): we don't store just the row ref
+ anymore, but a struct with the row ref and additional info,
+ (set_destination_row): handle drops on empty space and some
+ style fixes,
+ (get_logical_dest_row): also return path_down_mode/drop_append_mode
+ flags, handle dropping childs on their new parents, rewrite
+ drop append handling into something saner,
+ (gtk_tree_view_drag_motion): show a "drop possible arrow" on empty
+ spaces,
+ (gtk_tree_view_drag_drop): updates for updated backend,
+ (gtk_tree_view_drag_data_received): updates for updated backend,
+ path down mode (treestore DnD) handling,
+ (gtk_tree_view_set_drag_dest_row): set empty_view_drop flag,
+ when we are trying to drop a row on an empty model,
+ (gtk_tree_view_get_drag_dest_row): handle empty_view_drop flag.
+
+ * gtk/gtkliststore.c (gtk_list_store_drag_data_received),
+ (gtk_list_store_row_drop_possible): style and drop-append fixes.
+
+ * gtk/gtktreestore.c (gtk_tree_store_drag_data_received): ditto.
+
2003-09-08 Alexander Larsson <alexl@redhat.com>
* gtk/gtkeventbox.[hc]:
+Wed Sep 10 01:06:44 2003 Kristian Rietveld <kris@gtk.org>
+
+ Big TreeView DnD fixage, makes drops on empty models work, makes
+ TreeStore DnD work and gets rid of gtk-tree-model-drop-append.
+ Related bugs #95362 and #113314. I don't want to touch this code
+ ever again.
+
+ * gtk/gtktreeprivate.h (GtkTreePrivate): add empty_view_drop field.
+
+ * gtk/gtktreednd.c (gtk_tree_get_row_drag_data): add check
+ for selection_data->length.
+
+ * gtk/gtktreeview.c (struct DestRow), (dest_row_free),
+ (set_dest_row), (get_dest_row): we don't store just the row ref
+ anymore, but a struct with the row ref and additional info,
+ (set_destination_row): handle drops on empty space and some
+ style fixes,
+ (get_logical_dest_row): also return path_down_mode/drop_append_mode
+ flags, handle dropping childs on their new parents, rewrite
+ drop append handling into something saner,
+ (gtk_tree_view_drag_motion): show a "drop possible arrow" on empty
+ spaces,
+ (gtk_tree_view_drag_drop): updates for updated backend,
+ (gtk_tree_view_drag_data_received): updates for updated backend,
+ path down mode (treestore DnD) handling,
+ (gtk_tree_view_set_drag_dest_row): set empty_view_drop flag,
+ when we are trying to drop a row on an empty model,
+ (gtk_tree_view_get_drag_dest_row): handle empty_view_drop flag.
+
+ * gtk/gtkliststore.c (gtk_list_store_drag_data_received),
+ (gtk_list_store_row_drop_possible): style and drop-append fixes.
+
+ * gtk/gtktreestore.c (gtk_tree_store_drag_data_received): ditto.
+
2003-09-08 Alexander Larsson <alexl@redhat.com>
* gtk/gtkeventbox.[hc]:
/* dest was the first spot in the list; which means we are supposed
* to prepend.
*/
- gtk_list_store_prepend (GTK_LIST_STORE (tree_model),
- &dest_iter);
+ gtk_list_store_prepend (list_store, &dest_iter);
retval = TRUE;
}
else
{
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
- &dest_iter,
- prev))
+ if (gtk_tree_model_get_iter (tree_model, &dest_iter, prev))
{
GtkTreeIter tmp_iter = dest_iter;
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model), "gtk-tree-model-drop-append")))
- gtk_list_store_append (GTK_LIST_STORE (tree_model), &dest_iter);
- else
- gtk_list_store_insert_after (GTK_LIST_STORE (tree_model),
- &dest_iter, &tmp_iter);
+ gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
retval = TRUE;
}
}
- g_object_set_data (G_OBJECT (tree_model), "gtk-tree-model-drop-append",
- NULL);
-
gtk_tree_path_free (prev);
/* If we succeeded in creating dest_iter, copy data from src
++col;
}
- dest_iter.stamp = GTK_LIST_STORE (tree_model)->stamp;
+ dest_iter.stamp = list_store->stamp;
G_SLIST (dest_iter.user_data)->data = copy_head;
- path = gtk_list_store_get_path (GTK_TREE_MODEL (tree_model), &dest_iter);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_model), path, &dest_iter);
+ path = gtk_list_store_get_path (tree_model, &dest_iter);
+ gtk_tree_model_row_changed (tree_model, path, &dest_iter);
gtk_tree_path_free (path);
}
}
retval = TRUE;
out:
- gtk_tree_path_free (src_path);
+ if (src_path)
+ gtk_tree_path_free (src_path);
return retval;
}
if (selection_data->target != gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
return FALSE;
+ if (selection_data->length < 0)
+ return FALSE;
+
trd = (void*) selection_data->data;
if (tree_model)
guint has_rules : 1;
guint mark_rows_col_dirty : 1;
+ /* for DnD */
+ guint empty_view_drop : 1;
+
guint ctrl_pressed : 1;
guint shift_pressed : 1;
gtk_tree_path_free (parent);
parent = NULL;
- gtk_tree_store_prepend (GTK_TREE_STORE (tree_model),
+ gtk_tree_store_prepend (tree_store,
&dest_iter,
dest_parent_p);
}
else
{
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
- &dest_iter,
- prev))
+ if (gtk_tree_model_get_iter (tree_model, &dest_iter, prev))
{
GtkTreeIter tmp_iter = dest_iter;
- if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model), "gtk-tree-model-drop-append")))
- {
- GtkTreeIter parent;
-
- if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (tree_model), &parent, &tmp_iter))
- gtk_tree_store_append (GTK_TREE_STORE (tree_model),
- &dest_iter, &parent);
- else
- gtk_tree_store_append (GTK_TREE_STORE (tree_model),
- &dest_iter, NULL);
- }
- else
- gtk_tree_store_insert_after (GTK_TREE_STORE (tree_model),
- &dest_iter,
- NULL,
- &tmp_iter);
- retval = TRUE;
+ gtk_tree_store_insert_after (tree_store, &dest_iter, NULL,
+ &tmp_iter);
+ retval = TRUE;
}
}
- g_object_set_data (G_OBJECT (tree_model), "gtk-tree-model-drop-append",
- NULL);
-
gtk_tree_path_free (prev);
/* If we succeeded in creating dest_iter, walk src_iter tree branch,
#include "gtktreemodelsort.h"
#define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog"
+
#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
#define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
return NULL;
}
+typedef struct
+{
+ GtkTreeRowReference *dest_row;
+ gboolean path_down_mode;
+ gboolean empty_view_drop;
+ gboolean drop_append_mode;
+}
+DestRow;
+
+static void
+dest_row_free (gpointer data)
+{
+ DestRow *dr = (DestRow *)data;
+
+ gtk_tree_row_reference_free (dr->dest_row);
+ g_free (dr);
+}
+
static void
set_dest_row (GdkDragContext *context,
GtkTreeModel *model,
- GtkTreePath *dest_row)
+ GtkTreePath *dest_row,
+ gboolean path_down_mode,
+ gboolean empty_view_drop,
+ gboolean drop_append_mode)
{
- g_object_set_data_full (G_OBJECT (context),
- "gtk-tree-view-dest-row",
- dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
- (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
+ DestRow *dr;
+
+ if (!dest_row)
+ {
+ g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
+ NULL, NULL);
+ return;
+ }
+
+ dr = g_new0 (DestRow, 1);
+
+ dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
+ dr->path_down_mode = path_down_mode;
+ dr->empty_view_drop = empty_view_drop;
+ dr->drop_append_mode = drop_append_mode;
+
+ g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
+ dr, (GDestroyNotify) dest_row_free);
}
static GtkTreePath*
-get_dest_row (GdkDragContext *context)
+get_dest_row (GdkDragContext *context,
+ gboolean *path_down_mode)
{
- GtkTreeRowReference *ref =
+ DestRow *dr =
g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
- if (ref)
- return gtk_tree_row_reference_get_path (ref);
+ if (dr)
+ {
+ GtkTreePath *path = NULL;
+
+ if (path_down_mode)
+ *path_down_mode = dr->path_down_mode;
+
+ if (dr->dest_row)
+ path = gtk_tree_row_reference_get_path (dr->dest_row);
+ else if (dr->empty_view_drop)
+ path = gtk_tree_path_new_from_indices (0, -1);
+ else
+ path = NULL;
+
+ if (path && dr->drop_append_mode)
+ gtk_tree_path_next (path);
+
+ return path;
+ }
else
return NULL;
}
TreeViewDragInfo *di;
GtkWidget *widget;
GtkTreePath *old_dest_path = NULL;
+ gboolean can_drop = FALSE;
*suggested_action = 0;
*target = GDK_NONE;
&path,
&pos))
{
- /* can't drop here */
+ gint n_children;
+ GtkTreeModel *model;
+
remove_open_timeout (tree_view);
- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
- NULL,
- GTK_TREE_VIEW_DROP_BEFORE);
+ /* the row got dropped on empty space, let's setup a special case
+ */
if (path)
gtk_tree_path_free (path);
- /* don't propagate to parent though */
- return TRUE;
+ model = gtk_tree_view_get_model (tree_view);
+
+ n_children = gtk_tree_model_iter_n_children (model, NULL);
+ if (n_children)
+ {
+ pos = GTK_TREE_VIEW_DROP_AFTER;
+ path = gtk_tree_path_new_from_indices (n_children - 1, -1);
+ }
+ else
+ {
+ pos = GTK_TREE_VIEW_DROP_BEFORE;
+ path = gtk_tree_path_new_from_indices (0, -1);
+ }
+
+ can_drop = TRUE;
+
+ goto out;
}
g_assert (path);
gtk_tree_path_free (old_dest_path);
if (TRUE /* FIXME if the location droppable predicate */)
+ {
+ can_drop = TRUE;
+ }
+
+out:
+ if (can_drop)
{
GtkWidget *source_widget;
*suggested_action = context->suggested_action;
-
source_widget = gtk_drag_get_source_widget (context);
if (source_widget == widget)
{
/* Default to MOVE, unless the user has
- * pressed ctrl or alt to affect available actions
+ * pressed ctrl or shift to affect available actions
*/
if ((context->actions & GDK_ACTION_MOVE) != 0)
*suggested_action = GDK_ACTION_MOVE;
return TRUE;
}
-static GtkTreePath*
-get_logical_dest_row (GtkTreeView *tree_view)
+static GtkTreePath*
+get_logical_dest_row (GtkTreeView *tree_view,
+ gboolean *path_down_mode,
+ gboolean *drop_append_mode)
{
/* adjust path to point to the row the drop goes in front of */
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
+ g_return_val_if_fail (path_down_mode != NULL, NULL);
+ g_return_val_if_fail (drop_append_mode != NULL, NULL);
+
+ *path_down_mode = FALSE;
+ *drop_append_mode = 0;
+
gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
if (path == NULL)
; /* do nothing */
else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
- {
- /* get first child, drop before it */
- gtk_tree_path_down (path);
- }
+ *path_down_mode = TRUE;
else
{
GtkTreeIter iter;
g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
- gtk_tree_model_get_iter (model, &iter, path);
-
- if (!gtk_tree_model_iter_next (model, &iter))
- g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
- GINT_TO_POINTER (1));
+ if (!gtk_tree_model_get_iter (model, &iter, path) ||
+ !gtk_tree_model_iter_next (model, &iter))
+ *drop_append_mode = 1;
else
{
- g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
- NULL);
- gtk_tree_path_next (path);
- }
+ *drop_append_mode = 0;
+ gtk_tree_path_next (path);
+ }
}
return path;
gint y,
guint time)
{
+ gboolean empty;
GtkTreePath *path = NULL;
+ GtkTreeModel *model;
GtkTreeViewDropPosition pos;
GtkTreeView *tree_view;
GdkDragAction suggested_action = 0;
gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
- if (path == NULL)
+ /* we only know this *after* set_desination_row */
+ model = gtk_tree_view_get_model (tree_view);
+ empty = tree_view->priv->empty_view_drop;
+
+ if (path == NULL && !empty)
{
/* Can't drop here. */
gdk_drag_status (context, 0, time);
GdkAtom target = GDK_NONE;
TreeViewDragInfo *di;
GtkTreeModel *model;
+ gboolean path_down_mode;
+ gboolean drop_append_mode;
tree_view = GTK_TREE_VIEW (widget);
if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
return FALSE;
- path = get_logical_dest_row (tree_view);
+ path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
if (target != GDK_NONE && path != NULL)
{
* treat drag data receives as a drop.
*/
set_status_pending (context, 0);
-
- set_dest_row (context, model, path);
+ set_dest_row (context, model, path,
+ path_down_mode, tree_view->priv->empty_view_drop,
+ drop_append_mode);
}
if (path)
GtkTreeView *tree_view;
GtkTreePath *dest_row;
GdkDragAction suggested_action;
+ gboolean path_down_mode;
+ gboolean drop_append_mode;
tree_view = GTK_TREE_VIEW (widget);
* supposed to call drag_status, not actually paste in the
* data.
*/
- path = get_logical_dest_row (tree_view);
+ path = get_logical_dest_row (tree_view, &path_down_mode,
+ &drop_append_mode);
if (path == NULL)
suggested_action = 0;
+ else if (path_down_mode)
+ gtk_tree_path_down (path);
if (suggested_action)
{
if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
path,
selection_data))
- suggested_action = 0;
+ {
+ if (path_down_mode)
+ {
+ path_down_mode = FALSE;
+ gtk_tree_path_up (path);
+
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ path,
+ selection_data))
+ suggested_action = 0;
+ }
+ else
+ suggested_action = 0;
+ }
}
gdk_drag_status (context, suggested_action, time);
return;
}
- dest_row = get_dest_row (context);
+ dest_row = get_dest_row (context, &path_down_mode);
if (dest_row == NULL)
return;
+ if (selection_data->length >= 0)
+ {
+ if (path_down_mode)
+ {
+ gtk_tree_path_down (dest_row);
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ dest_row, selection_data))
+ gtk_tree_path_up (dest_row);
+ }
+ }
+
if (selection_data->length >= 0)
{
if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
gtk_tree_path_free (dest_row);
/* drop dest_row */
- set_dest_row (context, NULL, NULL);
+ set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
}
GtkTreeViewDropPosition pos)
{
GtkTreePath *current_dest;
+
/* Note; this function is exported to allow a custom DND
* implementation, so it can't touch TreeViewDragInfo
*/
current_dest = NULL;
if (tree_view->priv->drag_dest_row)
- current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+ {
+ current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+ gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+ }
- if (tree_view->priv->drag_dest_row)
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+ /* special case a drop on an empty model */
+ tree_view->priv->empty_view_drop = 0;
+
+ if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
+ && gtk_tree_path_get_depth (path) == 1
+ && gtk_tree_path_get_indices (path)[0] == 0)
+ {
+ gint n_children;
+
+ n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
+ NULL);
+
+ if (!n_children)
+ tree_view->priv->empty_view_drop = 1;
+ }
tree_view->priv->drag_dest_pos = pos;
if (tree_view->priv->drag_dest_row)
*path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
else
- *path = NULL;
+ {
+ if (tree_view->priv->empty_view_drop)
+ *path = gtk_tree_path_new_from_indices (0, -1);
+ else
+ *path = NULL;
+ }
}
if (pos)